import numpy as np
import pandas as pd
import biocircuits
import scipy.integrate
import scipy.signal
import bokeh.io
bokeh.io.output_notebook()
import panel as pn
pn.extension()
def style(p, autohide=False):
p.title.text_font="Helvetica"
p.title.text_font_size="16px"
p.title.align="center"
p.xaxis.axis_label_text_font="Helvetica"
p.yaxis.axis_label_text_font="Helvetica"
p.xaxis.axis_label_text_font_size="13px"
p.yaxis.axis_label_text_font_size="13px"
p.background_fill_alpha = 0
if autohide: p.toolbar.autohide=True
return p

import warnings
warnings.filterwarnings("ignore") # for those pesky pesky exponents/denominators
beta_x_slider = pn.widgets.FloatSlider(name="βx", start=0.1, end=10.0, step=0.1, value=0.7, width=100)
beta_y_slider = pn.widgets.FloatSlider(name="βy", start=0.1, end=10.0, step=0.1, value=0.7, width=100)
gamma_slider = pn.widgets.FloatSlider(name="γ", start=0.1, end=10.0, step=0.1, value=1.0, width=100)
k1_slider = pn.widgets.FloatSlider(name="κ1", start=0.01, end=3, step=0.1, value=1.5, width=100)
k2_slider = pn.widgets.FloatSlider(name="κ2", start=0.01, end=3, step=0.1, value=1.5, width=100)
n_xx_slider = pn.widgets.FloatSlider(name="n_xx", start=5, end=15.0, step=0.1, value=7, width=100)
n_xy_slider = pn.widgets.FloatSlider(name="n_xy", start=5, end=15.0, step=0.1, value=7, width=100)
n_yy_slider = pn.widgets.FloatSlider(name="n_yy", start=5, end=15.0, step=0.1, value=7, width=100)
n_yx_slider = pn.widgets.FloatSlider(name="n_yx", start=5, end=15.0, step=0.1, value=7, width=100)
x_range_slider = pn.widgets.RangeSlider(name="x-range", start=0, end=5, step=0.1, value=(0.2, 0.8), width=300)
y_range_slider = pn.widgets.RangeSlider(name="y-range", start=0, end=5, step=0.1, value=(0.2, 0.8), width=300)
@pn.depends(beta_x_slider.param.value, beta_y_slider.param.value, gamma_slider.param.value,
k1_slider.param.value, k2_slider.param.value,
n_xx_slider.param.value, n_xy_slider.param.value,
n_yy_slider.param.value, n_yx_slider.param.value,
x_range_slider.param.value, y_range_slider.param.value
)
def plotter(beta_x, beta_y, gamma, k1, k2, n_xx, n_xy, n_yy, n_yx, x_range, y_range):
nx, ny = 500, 500
x_min, x_max = x_range
y_min, y_max = y_range
x = np.linspace(x_min, x_max, nx)
y = np.linspace(y_min, y_max, ny)
# ............ STREAMPLOT ............
xx, yy = np.meshgrid(x, y, indexing="ij")
u = np.empty((nx, ny))
v = np.empty((nx, ny))
for i in range(nx):
for j in range(ny):
_x, _y = xx[i, j], yy[i, j]
num = 1 + _x**n_xx + _x**n_xx*(k1*_y)**n_yx
denom = (1+_x**n_xx) * (1+(k1*_y)**n_yx)
u[i, j] = beta_x * num/denom - _x
num = 1 + _y**n_yy + _y**n_yy*(k2*_x)**n_xy
denom = (1+_y**n_yy) * (1+(k2*_x)**n_xy)
v[i, j] = beta_y * num/denom - gamma * _y
p = bokeh.plotting.figure(
height=600, width=600,
title=(f"βx:{np.round(beta_x,2)} βy:{np.round(beta_y,2)} " +
f"γ:{np.round(gamma, 2)} κ1: {np.round(k1, 2)} " +
f"κ2: {np.round(k2, 2)}"))
p = biocircuits.streamplot(x, y, u, v, p=p, density=3.5, color="#74A0B2")
nx, ny = 100000, 100000
x = np.linspace(x_min, x_max+10, nx)
y = np.linspace(y_min, y_max+10, ny)
# ............ NULLCLINES ............
_x = 1/k2 * ((beta_y/gamma) / (y**(n_yy+1)-(beta_y/gamma)*(y**n_yy)+y) - 1)**(1/n_xy)
_y = 1/k1 * ((beta_x)/(x**(n_xx+1)-beta_x*(x**n_xx)+x) -1 )**(1/n_yx)
p.line(x, _y, line_color="#1c2641", line_width=1.5)
p.line(_x, y, line_color="#1c2641", line_width=1.5)
return style(p)
lay_widgets = pn.Row(pn.Column(beta_x_slider, beta_y_slider),
pn.Column(k1_slider, k2_slider),
pn.Column(n_xx_slider, n_xy_slider),
pn.Column(n_yx_slider, n_yy_slider),
pn.Column(gamma_slider, align="center"),
)
lay_range = pn.Column(x_range_slider, y_range_slider, align="center")
pn.Column(lay_widgets, plotter, lay_range)
I think there should be five crossings. I suspect I am not plotting enough xs and ys, but here are 3 suspiciously-stable looking points! This is a nice proof of concept. At first I thought there was "not a lot" you coould achieve with just two species but after seeing the range of nullcline crossings and vector fields, I think this is a wide range of behavior resulting from the addition of extra arrows.